/*
 * Team Huskies:
 * Aakanksha Gaur,
 * Alice Robinson,
 * Paul Winters,
 * Steve Bradshaw
 * Date: June 8th 2011
 */
#include <time.h>
#include <stdlib.h>
#include "process.h"

#define DISK_REQ 0
#define VID_REQ 1
#define KEY_REQ 2
#define MUTEX 3
#define SIGNAL_WAIT 4
#define SIGNAL 5
#define IDLE 6

/*
 * Creates the process.  The id is used to then create the associated PCB.
 * @return a new PCB which is associated to this process by ID.
 * the type char is c calculate, i interface, p producer, k consumer.  The
 * number of requests is generated randomly for each process up to the
 * number of steps.
 */
PCB_str create_p(int the_steps, int the_id, char the_process_type) {

	ProcessStr *new_process = malloc(sizeof(*new_process));

	//srand(time(NULL));
	//srand(time(NULL));
	int the_int_type;
	int the_requests = ((rand() % the_steps) / 10) + 10; //should we divide by 3 or 4 or more?
	int the_spacing = the_steps / the_requests;;
	int i = 0;
	int j = 1; //start spacing other than 0.  make 1 for now.
	new_process->array[the_requests][2];

	new_process->array = malloc(the_requests *sizeof(int *));
	if(new_process->array == NULL) {
		printf("out of memory\n");
	}

	//Allocate memory for the second dimension which is an integer size
	for(i = 0; i < the_requests; i++) {
		new_process->array[i][0] = (int)malloc(sizeof(int));
		new_process->array[i][1] = (int)malloc(sizeof(int));
		if(new_process->array[i] == NULL) {
			printf("out of memory\n");
		}
	}

	//Calculator Process, disk 0 & video 1

	//printf("\nMy process type is %i", the_process_type);

	if (the_process_type == 'c')
	{
		for (i = 0; i < the_requests; i++)
		{
			new_process->array[i][0] = j * the_spacing;	//what cycle to reques
			the_int_type = (rand() % 2);

			new_process->array[i][1] = the_int_type;	// the id of the request
			j++;
		}
	} //Interface Process, video 1 keyboard 2
	else if (the_process_type == 'i')
	{
		for (i = 0; i < the_requests; i++)
		{
			new_process->array[i][0] = j * the_spacing;
			the_int_type = (rand() % 2) + 1;
			new_process->array[i][1] = the_int_type;
			j++;
		}
	} //Producer Process, mutex 3 sig wait 4 signal 5
	else if (the_process_type == 'p')
	{
		for (i = 0; i < the_requests; i++)
		{
			new_process->array[i][0] = j * the_spacing;
			the_int_type = (rand() % 3) + 3; //rand 3, 4, 5
			new_process->array[i][1] = the_int_type;
			j++;
		}
	} //Consumer Process, mutex 3 sig wait 4 signal 6
	else if (the_process_type == 'k')
	{
		for (i = 0; i < the_requests; i++)
		{
			new_process->array[i][0] = j * the_spacing;
			the_int_type = (rand() % 3) + 3; //rand 3, 4, 5
			new_process->array[i][1] = the_int_type;
			j++;
		}
	} //Idle process, do nothing
	else
	{
		for (i = 0; i <= the_requests; i++)
		{
			new_process->array[i][0] = j * the_spacing;
			new_process->array[i][1] = IDLE;
			j++;
			//printf("h%i\n", array[i][1]);
		}
	}


	new_process->no_steps = the_steps;
	new_process->no_requests = the_requests;
	new_process->id = the_id;
	//printf("h%i\n", array[0][1]);
	return create_pcb(new_process->id, the_requests, new_process); //returns a PCB with this process
}

/*
 * Create the associated Process Control Block for this process.
 *
 */
PCB_str create_pcb(int the_id, int the_requests, ProcessStr *the_process) {

	PCB_str *new_pcb = malloc(sizeof(*new_pcb));


	new_pcb->pid = the_id;
	new_pcb->next_step = 0;
	new_pcb->state = 1; //default to ready.
	new_pcb->waiting_on = -1;
	new_pcb->owns = 1;
	new_pcb->requests_size = the_requests;
	new_pcb->my_process = the_process;
	new_pcb->request_no = 0;

	return *new_pcb;
}

/*
 * Used to do a context most context switches.  For semi's the setter will
 * to be used in addition.
 */
void update_pcb(PCB_str *pcb, int next_step, int state, int queue_id) {
	pcb->next_step = next_step;
	pcb->state = state;
	pcb->waiting_on = queue_id; //1 is the ready queue
}

/*
 * Sets the next step.
 */
void set_next_step(PCB_str *pcb, int the_next_step) {
	pcb->next_step = the_next_step;
}

/*
 * Get the next step to start execution.
 * @return is an integer value to start execution.
 */
int get_next_step(PCB_str *pcb) {
	return pcb->next_step;
}

/*
 * Set the state. 0=running, 1=ready, 2=interrupted, 3=blocked.
 */
void set_state(PCB_str *pcb, int the_state) {
	pcb->state = the_state;
}

/*
 * Get the state.
 * @return an integer state. 0=running, 1=ready, 2=interrupted, 3=blocked
 */
int get_state(PCB_str *pcb) {
	return pcb->state;
}

/*
 * Set the queue_id that is blocking this process. int 1 = ready.
 */
void set_waiting_on(PCB_str *pcb, int queue_id) {
	pcb->waiting_on = queue_id;
}

/**
 * Query which queue id the process is in.
 * @return an integer with queue id.
 */
int get_waiting_on(PCB_str *pcb) {
	return pcb->waiting_on;
}

/*
 * Setter for the semiphore it owns
 */
void set_sem_id(PCB_str *pcb, int the_sem_id) {
	pcb->owns = the_sem_id;
}

/*
 * Getter for which semiphore this process owns
 */
int get_sem_id(PCB_str *pcb) {
	return pcb->owns;
}
